-module(agent_daemon).

-behaviour(gen_server).

%%for test
-export([setup/0]).
-export([test_query/0]).

%% API
-export([start_link/0]).

-export([regist/1]).
%%-export([unregist/0]).
-export([deploy/1]).
-export([undeploy/1]).
-export([query_instance_acc/0]).
-export([query_instance_term/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
	 terminate/2, code_change/3]).
-include("agent.hrl").
-record(state, {container }).

test_query ()->
        gen_server:call(agent_daemon, {test_query}).

setup()->
        agent_daemon:regist( #container{name="container1",ip="localhost"}),
	agent_daemon:deploy( #app{name="app1",domain="",source="",target=""}),
	agent_daemon:test_query(),
	agent_daemon:unregist().
	
query_instance_term()->
        gen_server:call(agent_daemon, {query_instance_term} , 10000).
query_instance_acc()->
        gen_server:call(agent_daemon, {query_instance_acc} , 10000).

regist(Container)->
        gen_server:call(agent_daemon, {regist,Container}).
        
%%unregist()->
  %%     supervisor:terminate_child(agent_sup, agent_daemon),
  %%      supervisor:restart_child(agent_sup, agent_daemon),
  %%      supervisor:terminate_child(agent_sup, agent_report),
   %%     supervisor:restart_child(agent_sup, agent_report).

deploy(App)->
        gen_server:call(agent_daemon, {deploy,App} , infinity).

undeploy(App)->
        gen_server:call(agent_daemon, {undeploy,App}).
unregist()->
         gen_server:call(agent_daemon, {unregist}).

%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

%%====================================================================
%% gen_server callbacks
%%====================================================================

%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State} |
%%                         {ok, State, Timeout} |
%%                         ignore               |
%%                         {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([]) ->
        error_logger:info_msg("starting agent_daemon .....~n"),
	mnesia_op:add_agent_state_item(undefined,undefined,undefined),
        {ok, #state{container=undefined}}.

%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%%                                      {reply, Reply, State, Timeout} |
%%                                      {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, Reply, State} |
%%                                      {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call({test_query   }, _From ,State ) ->
	{reply , State , State };
handle_call( {query_instance_term}, _From , State ) ->
        
        {reply , request_monitor(State#state.container,"term"), State};	
        
handle_call( {query_instance_acc}, _From , State ) ->
        
        {reply , request_monitor(State#state.container,"acclu"), State};	

handle_call({regist,Container}=Msg, {Pid,_}=_From,State ) ->
                error_logger:info_msg("agent_daemon:recving a regist msg:~p~n",[Msg]),  
               case agent_report:regist( {Container,Pid}) of
                                        ok ->
						mnesia_op:add_agent_state_item( undefined, undefined, Container),
                                               {reply , ok  ,  #state{ container=Container } } ;
                                        Any ->
                                        { reply , {error , Any } , State }
               end ;


        
                
              
handle_call({deploy , App  }, _From ,State ) ->
        error_logger:info_msg("agent_daemon:recving a deploy msg:~p~n",[App]),
        case  do_deploy(App, State#state.container) of
                ok ->
                        error_logger:info_msg("agent_daemon:deploy success, notify agent_report~n"),
                        { reply , agent_report:deploy(App) , State } ;
                {error, Reason } ->
                        error_logger:info_msg("agent_daemon:deploy error , Reason=~p~n",[Reason]),
                        {reply ,{error,Reason} , State }
        end;
handle_call({unregist  }=Msg, _From ,State ) ->
        error_logger:info_msg("agent_daemon:recving a unregist:~p~n",[Msg]),
        case  do_undeploy(all, State#state.container) of
                ok ->
                        { reply , agent_report:undeploy(all) , init([]) } ;
                {error, Reason } ->
                        {reply ,{error, Reason }  , State }
        end;        
handle_call({undeploy , App  }, _From ,State ) ->
        error_logger:info_msg("agent_daemon:recving a undeploy msg:~p~n",[App]),
        case  do_undeploy(App, State#state.container) of
                ok ->
                        { reply , agent_report:undeploy(App#app.name) , State } ;
                {error, Reason } ->
                        {reply ,{error, Reason }  , State }
        end;


                

handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, State}
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast({unregist}, _State)->
        supervisor:terminate_child(agent_sup, agent_report),
        supervisor:restart_child(agent_sup, agent_report),
	mnesia_op:add_agent_state_item(undefined, undefined, undefined),
        {noreply , #state{container=undefined} } ;
handle_cast(_Msg, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
%%                                       {noreply, State, Timeout} |
%%                                       {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
    ok.

%%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------


do_deploy(App,Container)->
    %%    error_logger:info_msg("agent_daemon:execute script/deploy.sh ~n"),
        Command= io_lib:format("sh script/deploy.sh ~s ~s ~s",
                        [Container#container.home,
                                App#app.source , 
                                App#app.target]),
    %%    error_logger:info_msg("agent_daemon:Command=~p~n",[Command]),
        case os:cmd(Command )  of
               [] ->
      %%                  error_logger:info_msg("agent_daemon:execute script/deploy.sh  success ~n"),
                        case   agent_f5_proxy:add_domain_mapping({App#app.domain,
                                                                      Container#container.ip , 
                                                                      Container#container.port}) of
                               ok ->
                                 ok;
                               {error , Any } ->
                                  error_logger:info_msg("add_domain_mapping error , Reason=~p ~n",[Any]),
                                  { error, Any }
                        end;
               Reason ->
                        error_logger:info_msg("agent_daemon:execute script/deploy.sh  error , Reason=~p~n",[Reason]),
                        {error , Reason } 
        end.
        
do_undeploy(all,Container)->
        agent_f5_proxy:delete_domain_mapping({all ,Container#container.ip,Container#container.port } );        
do_undeploy(App,Container)->
        agent_f5_proxy:delete_domain_mapping({App#app.domain,Container#container.ip,Container#container.port}) .
        
request_monitor(Container,Type)->
        Url="http://localhost:"++Container#container.port++"/get_stat_data?type="++Type,
 %%       error_logger:info_msg("Url=~s~n",[Url]),                        

        case  http:request(Url) of
                {ok , {_,_,Body}}=Msg ->
  %%                      error_logger:info_msg("Msg=~p~n",[Msg]),
                         parse_body(Body)  ;
                Any ->
                        Any
        end.
        
        


%%app_name=wei.com&cpu=100.00&up=792&down=708&pv=1
%%app_name=wei.com&cpu=100.00&up=792&down=708&pv=1
        
parse_body(Body)->
    %%    error_logger:info_msg("Body=~p~n",[Body]),
        lists:map( fun(Line)->
    %%              error_logger:info_msg("Line=~p~n",[Line]),
                                 case string:tokens(Line,"&") of
                                        [P1,P2,P3,P4,P5] ->
                                                ["app_name",AppName]=string:tokens(P1,"="),
                                                ["cpu",Cpu]=string:tokens(P2,"="),
%%                                                {C,_} = string:to_integer(Cpu),
                                                ["up",Up]=string:tokens(P3,"="),
                                                {U,_} = string:to_integer(Up),
                                                ["down",Down]=string:tokens(P4,"="),
                                                {D,_} = string:to_integer(Down),
                                                ["pv",Pv]=string:tokens(P5,"="), 
                                                {P,_} = string:to_integer(Pv), 
                                                {AppName, #acc_runtime{cpu=Cpu,
                                                                        up=U,
                                                                        down=D,
                                                                        pv=P}}
                                 end
                                
                        end,
                  string:tokens(Body , "\n")).
                
        
        
 
	
        
        
        
        
        
        
        
        
        
        
        
